/* eslint-disable no-redeclare */
/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable max-len */
/* eslint-disable no-var */
import mxgraph from 'src/pages/mxgraph/graph/index';
import Base64 from 'src/pages/mxgraph/graph/Base64';
import { Graph } from 'src/pages/mxgraph/graph/Graph';
import { ChangePageSetup } from 'src/pages/mxgraph/graph/EditorUi';

const {
  mxGraph,
  mxConstants,
  mxGraphHandler,
  mxEvent,
  mxPoint,
  mxEventObject,
  mxCodec,
  mxUtils,
  mxResources,
  mxEventSource,
  mxClient,
  mxPopupMenu,
  mxGraphView,
  mxConnectionHandler,
  mxCellMarker,
  mxPopupMenuHandler,
  mxUndoManager,
  mxRectangle,
  mxRectangleShape,
  mxPolyline,
  mxPrintPreview,
} = mxgraph;

/**
 * Editor constructor executed on page load.
 */
const Editor = function (chromeless, themes, model, graph, editable) {
  mxEventSource.call(this);
  this.chromeless = chromeless != null ? chromeless : this.chromeless;
  this.initStencilRegistry();
  this.graph = graph || this.createGraph(themes, model);
  this.editable = editable != null ? editable : !chromeless;
  this.undoManager = this.createUndoManager();
  this.status = '';

  this.getOrCreateFilename = function () {
    //// 大图默认的名称:之前的
    //// return this.filename || mxResources.get('drawing', [Editor.pageCounter]) + '.xml';
    //// 新的
    return this.filename;
  };

  this.getFilename = function () {
    return this.filename;
  };

  //// Sets the status and fires a statusChanged event
  this.setStatus = function (value) {
    this.status = value;
    this.fireEvent(new mxEventObject('statusChanged'));
  };

  //// Returns the current status
  this.getStatus = function () {
    return this.status;
  };

  //// Updates modified state if graph changes
  this.graphChangeListener = function (sender, eventObject) {
    var edit = eventObject != null ? eventObject.getProperty('edit') : null;

    //// if (edit == null || !edit.ignoreEdit) {
    ////   let projectId = proxy.activeProjectId;
    ////   let project = proxy.projects.get(projectId);
    ////   project.config.xml.forEach(item => {
    ////     if (item.id === project.ui.editorUI.tabId) {
    ////       item.data = mxUtils.getPrettyXml(this.getGraphXml());
    ////     }
    ////   });
    ////   this.setModified(true);
    //// }
  };

  this.graph.getModel().addListener(
    mxEvent.CHANGE,
    mxUtils.bind(this, function () {
      this.graphChangeListener.apply(this, arguments);
    })
  );

  //// Sets persistent graph state defaults
  this.graph.resetViewOnRootChange = false;
  this.init();
};

/**
 * Counts open editor tabs (must be global for cross-window access)
 */
Editor.pageCounter = 0;

//// Cross-domain window access is not allowed in FF, so if we
//// were opened from another domain then this will fail.
(function () {
  try {
    var op = window;

    while (
      op.opener != null &&
      typeof op.opener.Editor !== 'undefined' &&
      !isNaN(op.opener.Editor.pageCounter) &&
      //// Workaround for possible infinite loop in FF https:////drawio.atlassian.net/browse/DS-795
      op.opener != op
    ) {
      op = op.opener;
    }

    //// Increments the counter in the first opener in the chain
    if (op != null) {
      op.Editor.pageCounter++;
      Editor.pageCounter = op.Editor.pageCounter;
    }
  } catch (e) {
    //// ignore
  }
})();

/**
 * Specifies if local storage should be used (eg. on the iPad which has no filesystem)
 */
Editor.useLocalStorage = typeof Storage != 'undefined' && mxClient.IS_IOS;

/**
 * Images below are for lightbox and embedding toolbars.
 */
Editor.helpImage = mxClient.IS_SVG
  ? ''
  : IMAGE_PATH + '/help.png';

/**
 * Sets the default font size.
 */
Editor.checkmarkImage = mxClient.IS_SVG
  ? ''
  : IMAGE_PATH + '/checkmark.gif';

/**
 * Images below are for lightbox and embedding toolbars.
 */
Editor.maximizeImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.zoomOutImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.zoomInImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.zoomFitImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.layersImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.previousImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.nextImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.editImage = mxClient.IS_SVG
  ? ''
  : IMAGE_PATH + '/edit.gif';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.zoomOutLargeImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.zoomInLargeImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.actualSizeLargeImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.printLargeImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.layersLargeImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.closeLargeImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.editLargeImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.previousLargeImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.nextLargeImage =
  '';

/**
 * Specifies the image to be used for the refresh button.
 */
Editor.refreshLargeImage =
  '';

/**
 * Specifies the image to be used for the back button.
 */
Editor.backLargeImage =
  '';

/**
 * Specifies the image to be used for the back button.
 */
Editor.fullscreenLargeImage =
  '';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.ctrlKey = mxClient.IS_MAC ? 'Cmd' : 'Ctrl';

/**
 * Specifies if the diagram should be saved automatically if possible. Default
 * is true.
 */
Editor.popupsAllowed = true;

/**
 * Editor inherits from mxEventSource
 */
mxUtils.extend(Editor, mxEventSource);

/**
 * Stores initial state of mxClient.NO_FO.
 */
Editor.prototype.originalNoForeignObject = mxClient.NO_FO;

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.prototype.transparentImage = mxClient.IS_SVG
  ? ''
  : IMAGE_PATH + '/transparent.gif';

/**
 * Specifies if the canvas should be extended in all directions. Default is true.
 */
Editor.prototype.extendCanvas = true;

/**
 * Specifies if the app should run in chromeless mode. Default is false.
 * This default is only used if the contructor argument is null.
 */
Editor.prototype.chromeless = false;

/**
 * Specifies the order of OK/Cancel buttons in dialogs. Default is true.
 * Cancel first is used on Macs, Windows/Confluence uses cancel last.
 */
Editor.prototype.cancelFirst = true;

/**
 * Specifies if the editor is enabled. Default is true.
 */
Editor.prototype.enabled = true;

/**
 * Contains the name which was used for the last save. Default value is null.
 */
Editor.prototype.filename = null;

/**
 * Contains the current modified state of the diagram. This is false for
 * new diagrams and after the diagram was saved.包含关系图的当前修改状态,大图当前如果被修改了，状态为:true;
 */
Editor.prototype.modified = false;

/**
 * Specifies if the diagram should be saved automatically if possible. Default
 * is true.自动保存
 */
Editor.prototype.autosave = true;

/**
 * Specifies the top spacing for the initial page view. Default is 0.
 */
Editor.prototype.initialTopSpacing = 0;

/**
 * Specifies the app name. Default is document.title.
 */
Editor.prototype.appName = document.title;

/**
 * 新建项目的path
 * @type {null}
 */
Editor.prototype.projectName = null;

Editor.prototype.projectPath = null;

Editor.prototype.description = null;

/**
 *
 */
Editor.prototype.editBlankUrl =
  window.location.protocol + '////' + window.location.host + '/';

/**
 * Default value for the graph container overflow style.
 */
Editor.prototype.defaultGraphOverflow = 'hidden';

/**
 * Initializes the environment.
 */
Editor.prototype.init = function () {
};

/**
 * Sets the XML node for the current diagram.
 */
Editor.prototype.isChromelessView = function () {
  return this.chromeless;
};

/**
 * Sets the XML node for the current diagram.自动保存xml文件
 */
Editor.prototype.setAutosave = function (value) {
  this.autosave = value;
  this.fireEvent(new mxEventObject('autosaveChanged'));
};

/**
 *
 */
Editor.prototype.getEditBlankUrl = function (params) {
  return this.editBlankUrl + params;
};

/**
 *
 */
Editor.prototype.editAsNew = function (xml, title) {
  var p = title != null ? '?title=' + encodeURIComponent(title) : '';

  if (urlParams['ui'] != null) {
    p += (p.length > 0 ? '&' : '?') + 'ui=' + urlParams['ui'];
  }

  if (this.editorWindow != null && !this.editorWindow.closed) {
    this.editorWindow.focus();
  } else {
    if (
      typeof window.postMessage !== 'undefined' &&
      (document.documentMode == null || document.documentMode >= 10)
    ) {
      if (this.editorWindow == null) {
        mxEvent.addListener(
          window,
          'message',
          mxUtils.bind(this, function (evt) {
            if (evt.data == 'ready' && evt.source == this.editorWindow) {
              this.editorWindow.postMessage(xml, '*');
            }
          })
        );
      }

      this.editorWindow = this.graph.openLink(
        this.getEditBlankUrl(p + (p.length > 0 ? '&' : '?') + 'client=1'),
        null,
        true
      );
    } else {
      this.editorWindow = this.graph.openLink(
        this.getEditBlankUrl(p) + '#R' + encodeURIComponent(xml)
      );
    }
  }
};

/**
 * Sets the XML node for the current diagram.
 */
Editor.prototype.createGraph = function (themes, model) {
  let graph = new Graph(null, model, null, null, themes);
  graph.transparentBackground = false;

  //// Opens all links in a new window while editing
  if (!this.chromeless) {
    graph.isBlankLink = function (href) {
      return !this.isExternalProtocol(href);
    };
  }

  return graph;
};

/**
 * Sets the XML node for the current diagram.
 */
Editor.prototype.resetGraph = function () {
  //// this.graph.gridEnabled = !this.isChromelessView() || urlParams['grid'] == '1';
  this.graph.gridEnabled = false;
  this.graph.graphHandler.guidesEnabled = true;
  this.graph.setTooltips(false); //// 是否显示提示,默认显示Cell的名称
  this.graph.setConnectable(true); //// 是否允许Cells通过其中部的连接点新建连接,false则通过连接线连接
  this.graph.foldingEnabled = true;
  this.graph.scrollbars = this.graph.defaultScrollbars;
  this.graph.pageVisible = this.graph.defaultPageVisible;
  this.graph.pageBreaksVisible = this.graph.pageVisible;
  this.graph.preferPageSize = this.graph.pageBreaksVisible;
  this.graph.background = null;
  this.graph.pageScale = mxGraph.prototype.pageScale;
  this.graph.pageFormat = mxGraph.prototype.pageFormat;
  this.graph.currentScale = 1;
  this.graph.currentTranslate.x = 0;
  this.graph.currentTranslate.y = 0;
  this.updateGraphComponents();
  this.graph.view.setScale(1);
};

/**
 * Sets the XML node for the current diagram.
 */
Editor.prototype.readGraphState = function (node) {
  this.graph.gridEnabled =
    node.getAttribute('grid') != '0' &&
    (!this.isChromelessView() || urlParams['grid'] == '1');
  this.graph.gridSize =
    parseFloat(node.getAttribute('gridSize')) || mxGraph.prototype.gridSize;
  this.graph.graphHandler.guidesEnabled = node.getAttribute('guides') != '0';
  this.graph.setTooltips(node.getAttribute('tooltips') != '0');
  this.graph.setConnectable(node.getAttribute('connect') != '0');
  this.graph.connectionArrowsEnabled = node.getAttribute('arrows') != '0';
  this.graph.foldingEnabled = node.getAttribute('fold') != '0';

  if (this.isChromelessView() && this.graph.foldingEnabled) {
    this.graph.foldingEnabled = urlParams['nav'] == '1';
    this.graph.cellRenderer.forceControlClickHandler = this.graph.foldingEnabled;
  }

  var ps = parseFloat(node.getAttribute('pageScale'));

  if (!isNaN(ps) && ps > 0) {
    this.graph.pageScale = ps;
  } else {
    this.graph.pageScale = mxGraph.prototype.pageScale;
  }

  if (!this.graph.isLightboxView()) {
    var pv = node.getAttribute('page');

    if (pv != null) {
      this.graph.pageVisible = pv != '0';
    } else {
      this.graph.pageVisible = this.graph.defaultPageVisible;
    }
  } else {
    this.graph.pageVisible = false;
  }

  this.graph.pageBreaksVisible = this.graph.pageVisible;
  this.graph.preferPageSize = this.graph.pageBreaksVisible;

  var pw = parseFloat(node.getAttribute('pageWidth'));
  var ph = parseFloat(node.getAttribute('pageHeight'));

  if (!isNaN(pw) && !isNaN(ph)) {
    this.graph.pageFormat = new mxRectangle(0, 0, pw, ph);
  }

  //// Loads the persistent state settings
  var bg = node.getAttribute('background');

  if (bg != null && bg.length > 0) {
    this.graph.background = bg;
  } else {
    this.graph.background = null;
  }
};

/**
 * Sets the XML node for the current diagram.
 */
Editor.prototype.setGraphXml = function (node) {
  if (node != null) {
    var dec = new mxCodec(node.ownerDocument);

    if (node.nodeName == 'mxGraphModel') {
      this.graph.model.beginUpdate();

      try {
        this.graph.model.clear();
        this.graph.view.scale = 1;
        this.readGraphState(node);
        this.updateGraphComponents();
        dec.decode(node, this.graph.getModel());
      } finally {
        this.graph.model.endUpdate();
      }

      this.fireEvent(new mxEventObject('resetGraphView'));
    } else if (node.nodeName == 'root') {
      this.resetGraph();

      //// Workaround for invalid XML output in Firefox 20 due to bug in mxUtils.getXml
      var wrapper = dec.document.createElement('mxGraphModel');
      wrapper.appendChild(node);

      dec.decode(wrapper, this.graph.getModel());
      this.updateGraphComponents();
      this.fireEvent(new mxEventObject('resetGraphView'));
    } else {
      throw {
        message: mxResources.get('cannotOpenFile'),
        node: node,
        toString: function () {
          return this.message;
        }
      };
    }
  } else {
    this.resetGraph();
    this.graph.model.clear();
    this.fireEvent(new mxEventObject('resetGraphView'));
  }
};

/**
 * Returns the XML node that represents the current diagram.
 */
Editor.prototype.getGraphXml = function (ignoreSelection) {
  ignoreSelection = ignoreSelection != null ? ignoreSelection : true;
  var node = null;

  if (ignoreSelection) {
    var enc = new mxCodec(mxUtils.createXmlDocument());
    node = enc.encode(this.graph.getModel());
  } else {
    node = this.graph.encodeCells(
      mxUtils.sortCells(
        this.graph.model.getTopmostCells(this.graph.getSelectionCells())
      )
    );
  }

  if (this.graph.view.translate.x != 0 || this.graph.view.translate.y != 0) {
    node.setAttribute(
      'dx',
      Math.round(this.graph.view.translate.x * 100) / 100
    );
    node.setAttribute(
      'dy',
      Math.round(this.graph.view.translate.y * 100) / 100
    );
  }

  node.setAttribute('grid', this.graph.isGridEnabled() ? '1' : '0');
  node.setAttribute('gridSize', this.graph.gridSize);
  node.setAttribute(
    'guides',
    this.graph.graphHandler.guidesEnabled ? '1' : '0'
  );
  node.setAttribute(
    'tooltips',
    this.graph.tooltipHandler.isEnabled() ? '1' : '0'
  );
  node.setAttribute(
    'connect',
    this.graph.connectionHandler.isEnabled() ? '1' : '0'
  );
  node.setAttribute('arrows', this.graph.connectionArrowsEnabled ? '1' : '0');
  node.setAttribute('fold', this.graph.foldingEnabled ? '1' : '0');
  node.setAttribute('page', this.graph.pageVisible ? '1' : '0');
  node.setAttribute('pageScale', this.graph.pageScale);
  node.setAttribute('pageWidth', this.graph.pageFormat.width);
  node.setAttribute('pageHeight', this.graph.pageFormat.height);

  if (this.graph.background != null) {
    node.setAttribute('background', this.graph.background);
  }

  return node;
};

/**
 * Keeps the graph container in sync with the persistent graph state
 */
Editor.prototype.updateGraphComponents = function () {
  var graph = this.graph;

  if (graph.container != null) {
    graph.view.validateBackground();
    graph.container.style.overflow = graph.scrollbars
      ? 'auto'
      : this.defaultGraphOverflow;

    this.fireEvent(new mxEventObject('updateGraphComponents'));
  }
};

/**
 * Sets the modified flag.
 */
Editor.prototype.setModified = function (value) {
  //// console.log('页面修改就执行:', value);
  //// 页面修改就执行 value 就为:true;
  if (value) {
    //// 设置倒计时，每隔1分钟自动保存一次
    setTimeout(() => {
      //// console.log('this.name:', this.filename, this._id);
      var obj = {
        id: this._id,
        name: this.filename
      };
      if (this._id != null) {
        //// EditorUi.save(obj);
        this.setStatus(
          mxUtils.htmlEntities(mxResources.get('allChangesSaved'))
        );
      } else {
        //// 提示信息
        //// this.$message.info('内容已被修改');
        //// mxUtils.confirm('画布内容已被修改,请手动去保存,如果不保存，继续执行，数据将会丢失!');
        return false;
      }
    }, 5000);
    this.setStatus(
      mxUtils.htmlEntities(
        mxResources.get('modificationNotSavedClickHereToSave')
      )
    );
  }
  this.modified = value;
};

/**
 * Sets the filename.
 */
Editor.prototype.setFilename = function (value) {
  this.filename = value;
};

Editor.prototype.setProjectName = function (value) {
  this.projectName = value;
};

Editor.prototype.setProjectPath = function (value) {
  this.projectPath = value;
};

Editor.prototype.setDescription = function (value) {
  this.description = value;
};

/**
 * Creates and returns a new undo manager.
 */
Editor.prototype.createUndoManager = function () {
  var graph = this.graph;
  var undoMgr = new mxUndoManager();

  this.undoListener = function (sender, evt) {
    undoMgr.undoableEditHappened(evt.getProperty('edit'));
  };

  //// Installs the command history
  var listener = mxUtils.bind(this, function (sender, evt) {
    this.undoListener.apply(this, arguments);
  });

  graph.getModel().addListener(mxEvent.UNDO, listener);
  graph.getView().addListener(mxEvent.UNDO, listener);

  //// Keeps the selection in sync with the history
  var undoHandler = function (sender, evt) {
    var cand = graph.getSelectionCellsForChanges(
      evt.getProperty('edit').changes
    );
    var model = graph.getModel();
    var cells = [];

    for (var i = 0; i < cand.length; i++) {
      if (graph.view.getState(cand[i]) != null) {
        cells.push(cand[i]);
      }
    }

    graph.setSelectionCells(cells);
  };

  undoMgr.addListener(mxEvent.UNDO, undoHandler);
  undoMgr.addListener(mxEvent.REDO, undoHandler);

  return undoMgr;
};

/**
 * Adds basic stencil set (no namespace).
 */
Editor.prototype.initStencilRegistry = function () {
};

/**
 * Creates and returns a new undo manager.
 */
Editor.prototype.destroy = function () {
  if (this.graph != null) {
    this.graph.destroy();
    this.graph = null;
  }
};

Editor.prototype.graphEditor = null;

/**
 * Class for asynchronously opening a new window and loading a file at the same
 * time. This acts as a bridge between the open dialog and the new editor.
 */
const OpenFile = function (done) {
  //// console.log(12312312)
  this.producer = null;
  this.consumer = null;
  this.done = done;
  this.args = null;
};

/**
 * Registers the editor from the new window.
 */
OpenFile.prototype.setConsumer = function (value) {
  this.consumer = value;
  this.execute();
};

/**
 * Sets the data from the loaded file.
 */
OpenFile.prototype.setData = function () {
  this.args = arguments;
  this.execute();
};

/**
 * Displays an error message.
 */
OpenFile.prototype.error = function (msg) {
  this.cancel(true);
  mxUtils.alert(msg);
};

/**
 * Consumes the data.
 */
OpenFile.prototype.execute = function () {
  console.log('执行了: ', this.consumer, this.args);
  if (this.consumer != null && this.args != null) {
    this.cancel(false);
    this.consumer.apply(this, this.args);
  }
};

/**
 * Cancels the operation.
 */
OpenFile.prototype.cancel = function (cancel) {
  if (this.done != null) {
    this.done(cancel != null ? cancel : true);
  }
};

/**
 * Basic dialogs that are available in the viewer (print dialog).
 */
function Dialog(
  editorUi,
  elt,
  w,
  h,
  modal,
  closable,
  onClose,
  noScroll,
  transparent,
  onResize,
  ignoreBgClick
) {
  var dx = 0;

  if (
    mxClient.IS_VML &&
    (document.documentMode == null || document.documentMode < 8)
  ) {
    //// Adds padding as a workaround for box model in older IE versions
    //// This needs to match the total padding of geDialog in CSS
    dx = 80;
  }

  w += dx;
  h += dx;

  var w0 = w;
  var h0 = h;

  //// clientHeight check is attempted fix for print dialog offset in viewer lightbox
  var ds = mxUtils.getDocumentSize();
  var dh = ds.height;
  var left = Math.max(1, Math.round((ds.width - w - 64) / 2));
  var top = Math.max(1, Math.round((dh - h - editorUi.footerHeight) / 3));

  //// Keeps window size inside available space
  if (!mxClient.IS_QUIRKS) {
    elt.style.maxHeight = '100%';
  }

  w = document.body != null ? Math.min(w, document.body.scrollWidth - 64) : w;
  h = Math.min(h, dh - 64);

  //// Increments zIndex to put subdialogs and background over existing dialogs and background
  if (editorUi.dialogs.length > 0) {
    this.zIndex += editorUi.dialogs.length * 2;
  }

  if (this.bg == null) {
    this.bg = editorUi.createDiv('background');
    this.bg.style.position = 'absolute';
    this.bg.style.background = Dialog.backdropColor;
    this.bg.style.height = dh + 'px';
    this.bg.style.right = '0px';
    this.bg.style.zIndex = this.zIndex - 2;

    mxUtils.setOpacity(this.bg, this.bgOpacity);

    if (mxClient.IS_QUIRKS) {
      new mxDivResizer(this.bg);
    }
  }

  var origin = mxUtils.getDocumentScrollOrigin(document);
  this.bg.style.left = origin.x + 'px';
  this.bg.style.top = origin.y + 'px';
  left += origin.x;
  top += origin.y;

  if (modal) {
    document.body.appendChild(this.bg);
  }

  var div = editorUi.createDiv(transparent ? 'geTransDialog' : 'geDialog');
  var pos = this.getPosition(left, top, w, h);
  left = pos.x;
  top = pos.y;
  //// 全局 dialog 的样式
  div.style.width = w + 60 + 'px';
  div.style.height = h + 60 + 'px'; //// 保存xml时，弹层的高度
  div.style.left = left + 0 + 'px';
  div.style.top = top + 'px';
  div.style.zIndex = this.zIndex;

  div.appendChild(elt);
  document.body.appendChild(div);

  //// Adds vertical scrollbars if needed
  if (!noScroll && elt.clientHeight > div.clientHeight - 64) {
    elt.style.overflowY = 'auto';
  }

  if (closable) {
    var img = document.createElement('img');

    img.setAttribute('src', Dialog.prototype.closeImage);
    img.setAttribute('title', mxResources.get('close'));
    img.className = 'geDialogClose';
    img.style.top = top + 14 + 'px';
    img.style.left = left + w + 38 - dx + 'px';
    img.style.zIndex = this.zIndex;

    mxEvent.addListener(
      img,
      'click',
      mxUtils.bind(this, function () {
        editorUi.hideDialog(true);
      })
    );

    document.body.appendChild(img);
    this.dialogImg = img;

    if (!ignoreBgClick) {
      mxEvent.addGestureListeners(
        this.bg,
        null,
        null,
        mxUtils.bind(this, function (evt) {
          editorUi.hideDialog(true);
        })
      );
    }
  }

  this.resizeListener = mxUtils.bind(this, function () {
    if (onResize != null) {
      var newWH = onResize();

      if (newWH != null) {
        w0 = w = newWH.w;
        h0 = h = newWH.h;
      }
    }

    var ds = mxUtils.getDocumentSize();
    dh = ds.height;
    this.bg.style.height = dh + 'px';

    left = Math.max(1, Math.round((ds.width - w - 64) / 2));
    top = Math.max(1, Math.round((dh - h - editorUi.footerHeight) / 3));
    w =
      document.body != null ? Math.min(w0, document.body.scrollWidth - 64) : w0;
    h = Math.min(h0, dh - 64);

    var pos = this.getPosition(left, top, w, h);
    left = pos.x;
    top = pos.y;

    div.style.left = left + 'px';
    div.style.top = top + 'px';
    div.style.width = w + 'px';
    div.style.height = h + 'px';

    //// Adds vertical scrollbars if needed
    if (!noScroll && elt.clientHeight > div.clientHeight - 64) {
      elt.style.overflowY = 'auto';
    }

    if (this.dialogImg != null) {
      this.dialogImg.style.top = top + 14 + 'px';
      this.dialogImg.style.left = left + w + 38 - dx + 'px';
    }
  });

  mxEvent.addListener(window, 'resize', this.resizeListener);

  this.onDialogClose = onClose;
  this.container = div;

  editorUi.editor.fireEvent(new mxEventObject('showDialog'));
}

/**
 *
 */
Dialog.backdropColor = 'white';

/**
 *
 */
Dialog.prototype.zIndex = mxPopupMenu.prototype.zIndex - 1;

/**
 *
 */
Dialog.prototype.noColorImage = !mxClient.IS_SVG
  ? IMAGE_PATH + '/nocolor.png'
  : '';

/**
 *
 */
Dialog.prototype.closeImage = !mxClient.IS_SVG
  ? IMAGE_PATH + '/close.png'
  : '';

/**
 *
 */
Dialog.prototype.clearImage = !mxClient.IS_SVG
  ? IMAGE_PATH + '/clear.gif'
  : '';

/**
 *
 */
Dialog.prototype.lockedImage = !mxClient.IS_SVG
  ? IMAGE_PATH + '/locked.png'
  : '';

/**
 *
 */
Dialog.prototype.unlockedImage = !mxClient.IS_SVG
  ? IMAGE_PATH + '/unlocked.png'
  : '';

/**
 * Removes the dialog from the DOM.
 */
Dialog.prototype.bgOpacity = 80;

/**
 * Removes the dialog from the DOM.
 */
Dialog.prototype.getPosition = function (left, top) {
  return new mxPoint(left, top);
};

/**
 * Removes the dialog from the DOM.
 */
Dialog.prototype.close = function (cancel, isEsc) {
  if (this.onDialogClose != null) {
    if (this.onDialogClose(cancel, isEsc) == false) {
      return false;
    }

    this.onDialogClose = null;
  }

  if (this.dialogImg != null) {
    this.dialogImg.parentNode.removeChild(this.dialogImg);
    this.dialogImg = null;
  }

  if (this.bg != null && this.bg.parentNode != null) {
    this.bg.parentNode.removeChild(this.bg);
  }

  mxEvent.removeListener(window, 'resize', this.resizeListener);
  this.container.parentNode.removeChild(this.container);
};

/**
 *
 */
var ErrorDialog = function (
  editorUi,
  title,
  message,
  buttonText,
  fn,
  retry,
  buttonText2,
  fn2,
  hide,
  buttonText3,
  fn3
) {
  hide = hide != null ? hide : true;

  var div = document.createElement('div');
  div.style.textAlign = 'center';

  if (title != null) {
    var hd = document.createElement('div');
    hd.style.padding = '0px';
    hd.style.margin = '0px';
    hd.style.fontSize = '18px';
    hd.style.paddingBottom = '16px';
    hd.style.marginBottom = '10px';
    hd.style.borderBottom = '1px solid #c0c0c0';
    hd.style.color = 'gray';
    hd.style.whiteSpace = 'nowrap';
    hd.style.textOverflow = 'ellipsis';
    hd.style.overflow = 'hidden';
    mxUtils.write(hd, title);
    hd.setAttribute('title', title);
    div.appendChild(hd);
  }

  var p2 = document.createElement('div');
  p2.style.lineHeight = '1.2em';
  p2.style.padding = '6px';
  p2.innerHTML = message;
  div.appendChild(p2);

  var btns = document.createElement('div');
  btns.style.marginTop = '12px';
  btns.style.textAlign = 'center';

  if (retry != null) {
    var retryBtn = mxUtils.button(mxResources.get('tryAgain'), function () {
      editorUi.hideDialog();
      retry();
    });
    retryBtn.className = 'geBtn';
    btns.appendChild(retryBtn);

    btns.style.textAlign = 'center';
  }

  if (buttonText3 != null) {
    var btn3 = mxUtils.button(buttonText3, function () {
      if (fn3 != null) {
        fn3();
      }
    });

    btn3.className = 'geBtn';
    btns.appendChild(btn3);
  }

  var btn = mxUtils.button(buttonText, function () {
    if (hide) {
      editorUi.hideDialog();
    }

    if (fn != null) {
      fn();
    }
  });

  btn.className = 'geBtn';
  btns.appendChild(btn);

  if (buttonText2 != null) {
    var mainBtn = mxUtils.button(buttonText2, function () {
      if (hide) {
        editorUi.hideDialog();
      }

      if (fn2 != null) {
        fn2();
      }
    });

    mainBtn.className = 'geBtn gePrimaryBtn';
    btns.appendChild(mainBtn);
  }

  this.init = function () {
    btn.focus();
  };

  div.appendChild(btns);

  this.container = div;
};

/**
 * Constructs a new print dialog.
 */
var PrintDialog = function (editorUi, title) {
  this.create(editorUi, title);
};

/**
 * Constructs a new print dialog.
 */
PrintDialog.prototype.create = function (editorUi) {
  var graph = editorUi.editor.graph;
  var row, td;

  var table = document.createElement('table');
  table.style.width = '100%';
  table.style.height = '100%';

  var thead = document.createElement('thead');
  var tr = document.createElement('tr');
  var th = document.createElement('th');

  table.appendChild(thead);
  thead.appendChild(tr);
  tr.appendChild(th);
  mxUtils.write(th, '打印'); //// 加标题'打印'
  th.style.fontSize = '18px';
  th.style.textAlign = 'center';
  th.setAttribute('colspan', '2');

  var tbody = document.createElement('tbody');

  row = document.createElement('tr');

  var onePageCheckBox = document.createElement('input');
  onePageCheckBox.setAttribute('type', 'checkbox');
  td = document.createElement('td');
  td.setAttribute('colspan', '2');
  td.style.fontSize = '10pt';
  td.appendChild(onePageCheckBox);

  var span = document.createElement('span');
  mxUtils.write(span, ' ' + mxResources.get('fitPage'));
  td.appendChild(span);

  mxEvent.addListener(span, 'click', function (evt) {
    onePageCheckBox.checked = !onePageCheckBox.checked;
    pageCountCheckBox.checked = !onePageCheckBox.checked;
    mxEvent.consume(evt);
  });

  mxEvent.addListener(onePageCheckBox, 'change', function () {
    pageCountCheckBox.checked = !onePageCheckBox.checked;
  });

  row.appendChild(td);
  tbody.appendChild(row);

  row = row.cloneNode(false);

  var pageCountCheckBox = document.createElement('input');
  pageCountCheckBox.setAttribute('type', 'checkbox');
  td = document.createElement('td');
  td.style.fontSize = '10pt';
  td.appendChild(pageCountCheckBox);

  var span = document.createElement('span');
  mxUtils.write(span, ' ' + mxResources.get('posterPrint') + ':');
  td.appendChild(span);

  mxEvent.addListener(span, 'click', function (evt) {
    pageCountCheckBox.checked = !pageCountCheckBox.checked;
    onePageCheckBox.checked = !pageCountCheckBox.checked;
    mxEvent.consume(evt);
  });

  row.appendChild(td);

  var pageCountInput = document.createElement('input');
  pageCountInput.setAttribute('value', '1');
  pageCountInput.setAttribute('type', 'number');
  pageCountInput.setAttribute('min', '1');
  pageCountInput.setAttribute('size', '4');
  pageCountInput.setAttribute('disabled', 'disabled');
  pageCountInput.style.width = '50px';

  td = document.createElement('td');
  td.style.fontSize = '10pt';
  td.appendChild(pageCountInput);
  mxUtils.write(td, ' ' + mxResources.get('pages') + ' (默认最大值)');
  row.appendChild(td);
  tbody.appendChild(row);

  mxEvent.addListener(pageCountCheckBox, 'change', function () {
    if (pageCountCheckBox.checked) {
      pageCountInput.removeAttribute('disabled');
    } else {
      pageCountInput.setAttribute('disabled', 'disabled');
    }

    onePageCheckBox.checked = !pageCountCheckBox.checked;
  });

  row = row.cloneNode(false);

  td = document.createElement('td');
  mxUtils.write(td, mxResources.get('pageScale') + ':');
  row.appendChild(td);

  td = document.createElement('td');
  var pageScaleInput = document.createElement('input');
  pageScaleInput.setAttribute('value', '100 %');
  pageScaleInput.setAttribute('size', '5');
  pageScaleInput.style.width = '50px';

  td.appendChild(pageScaleInput);
  row.appendChild(td);
  tbody.appendChild(row);

  row = document.createElement('tr');
  td = document.createElement('td');
  td.colSpan = 2;
  td.style.paddingTop = '20px';
  td.setAttribute('align', 'right');

  //// Overall scale for print-out to account for print borders in dialogs etc
  function preview(print) {
    var autoOrigin = onePageCheckBox.checked || pageCountCheckBox.checked;
    var printScale = parseInt(pageScaleInput.value) / 100;

    if (isNaN(printScale)) {
      printScale = 1;
      pageScaleInput.value = '100%';
    }

    //// Workaround to match available paper size in actual print output
    printScale *= 0.75;

    var pf = graph.pageFormat || mxConstants.PAGE_FORMAT_A4_PORTRAIT;
    var scale = 1 / graph.pageScale;

    if (autoOrigin) {
      var pageCount = onePageCheckBox.checked
        ? 1
        : parseInt(pageCountInput.value);

      if (!isNaN(pageCount)) {
        scale = mxUtils.getScaleForPageCount(pageCount, graph, pf);
      }
    }

    //// Negative coordinates are cropped or shifted if page visible
    var gb = graph.getGraphBounds();
    var border = 0;
    var x0 = 0;
    var y0 = 0;

    //// Applies print scale
    pf = mxRectangle.fromRectangle(pf);
    pf.width = Math.ceil(pf.width * printScale);
    pf.height = Math.ceil(pf.height * printScale);
    scale *= printScale;

    //// Starts at first visible page
    if (!autoOrigin && graph.pageVisible) {
      var layout = graph.getPageLayout();
      x0 -= layout.x * pf.width;
      y0 -= layout.y * pf.height;
    } else {
      autoOrigin = true;
    }

    var preview = PrintDialog.createPrintPreview(
      graph,
      scale,
      pf,
      border,
      x0,
      y0,
      autoOrigin
    );
    preview.open();

    if (print) {
      PrintDialog.printPreview(preview);
    }
  }

  var cancelBtn = mxUtils.button(mxResources.get('cancel'), function () {
    editorUi.hideDialog();
  });
  cancelBtn.className = 'geBtn';

  if (editorUi.editor.cancelFirst) {
    td.appendChild(cancelBtn);
  }

  if (PrintDialog.previewEnabled) {
    var previewBtn = mxUtils.button(mxResources.get('preview'), function () {
      editorUi.hideDialog();
      preview(false);
    });
    previewBtn.className = 'geBtn';
    td.appendChild(previewBtn);
  }

  var printBtn = mxUtils.button(
    mxResources.get(!PrintDialog.previewEnabled ? 'ok' : 'print'),
    function () {
      editorUi.hideDialog();
      preview(true);
    }
  );
  printBtn.className = 'geBtn gePrimaryBtn';
  td.appendChild(printBtn);

  if (!editorUi.editor.cancelFirst) {
    td.appendChild(cancelBtn);
  }

  row.appendChild(td);
  tbody.appendChild(row);

  table.appendChild(tbody);
  this.container = table;
};

/**
 * Constructs a new print dialog.
 */
PrintDialog.printPreview = function (preview) {
  try {
    if (preview.wnd != null) {
      var printFn = function () {
        preview.wnd.focus();
        preview.wnd.print();
        preview.wnd.close();
      };

      //// Workaround for Google Chrome which needs a bit of a
      //// delay in order to render the SVG contents
      //// Needs testing in production
      if (mxClient.IS_GC) {
        window.setTimeout(printFn, 500);
      } else {
        printFn();
      }
    }
  } catch (e) {
    //// ignores possible Access Denied
  }
};

/**
 * Constructs a new print dialog.
 */
PrintDialog.createPrintPreview = function (
  graph,
  scale,
  pf,
  border,
  x0,
  y0,
  autoOrigin
) {
  var preview = new mxPrintPreview(graph, scale, pf, border, x0, y0);
  preview.title = mxResources.get('preview');
  preview.printBackgroundImage = true;
  preview.autoOrigin = autoOrigin;
  var bg = graph.background;

  if (bg == null || bg == '' || bg == mxConstants.NONE) {
    bg = '#ffffff';
  }

  preview.backgroundColor = bg;

  var writeHead = preview.writeHead;

  //// Adds a border in the preview
  preview.writeHead = function (doc) {
    writeHead.apply(this, arguments);
    doc.writeln('<style type="text/css">');
    doc.writeln('@media screen {');
    doc.writeln('  body > div { padding:30px;box-sizing:content-box; }');
    doc.writeln('}');
    doc.writeln('</style>');
  };
  return preview;
};

/**
 * Specifies if the preview button should be enabled. Default is true.
 */
PrintDialog.previewEnabled = true;

/**
 * Constructs a new page setup dialog.
 */
var PageSetupDialog = function (editorUi) {
  var graph = editorUi.editor.graph;
  var row, td;

  var table = document.createElement('table');
  table.style.width = '100%';
  table.style.height = '100%';
  var tbody = document.createElement('tbody');

  row = document.createElement('tr');

  td = document.createElement('td');
  td.style.verticalAlign = 'top';
  td.style.fontSize = '10pt';
  mxUtils.write(td, mxResources.get('paperSize') + ':');

  row.appendChild(td);

  td = document.createElement('td');
  td.style.verticalAlign = 'top';
  td.style.fontSize = '10pt';

  var accessor = PageSetupDialog.addPageFormatPanel(
    td,
    'pagesetupdialog',
    graph.pageFormat
  );

  row.appendChild(td);
  tbody.appendChild(row);

  row = document.createElement('tr');

  td = document.createElement('td');
  mxUtils.write(td, mxResources.get('background') + ':');

  row.appendChild(td);

  td = document.createElement('td');
  td.style.whiteSpace = 'nowrap';

  var backgroundInput = document.createElement('input');
  backgroundInput.setAttribute('type', 'text');
  var backgroundButton = document.createElement('button');

  backgroundButton.style.width = '18px';
  backgroundButton.style.height = '18px';
  backgroundButton.style.marginRight = '20px';
  backgroundButton.style.backgroundPosition = 'center center';
  backgroundButton.style.display = 'inline-block'; //// 背景按钮
  backgroundButton.style.backgroundRepeat = 'no-repeat';

  var newBackgroundColor = graph.background;

  function updateBackgroundColor() {
    if (newBackgroundColor == null || newBackgroundColor == mxConstants.NONE) {
      backgroundButton.style.backgroundColor = '';
      backgroundButton.style.backgroundImage =
        "url('" + Dialog.prototype.noColorImage + "')";
    } else {
      backgroundButton.style.backgroundColor = newBackgroundColor;
      backgroundButton.style.backgroundImage = '';
    }
  }

  updateBackgroundColor();

  mxEvent.addListener(backgroundButton, 'click', function (evt) {
    editorUi.pickColor(newBackgroundColor || 'none', function (color) {
      newBackgroundColor = color;
      updateBackgroundColor();
    });
    mxEvent.consume(evt);
  });

  td.appendChild(backgroundButton);

  mxUtils.write(td, mxResources.get('gridSize') + ':');

  var gridSizeInput = document.createElement('input');
  gridSizeInput.setAttribute('type', 'number');
  gridSizeInput.setAttribute('min', '0');
  gridSizeInput.style.width = '40px';
  gridSizeInput.style.marginLeft = '6px';

  gridSizeInput.value = graph.getGridSize();
  td.appendChild(gridSizeInput);

  mxEvent.addListener(gridSizeInput, 'change', function () {
    var value = parseInt(gridSizeInput.value);
    gridSizeInput.value = Math.max(
      1,
      isNaN(value) ? graph.getGridSize() : value
    );
  });

  row.appendChild(td);
  tbody.appendChild(row);

  row = document.createElement('tr');
  td = document.createElement('td');

  mxUtils.write(td, mxResources.get('image') + ':');

  row.appendChild(td);
  td = document.createElement('td');

  var changeImageLink = document.createElement('a');
  changeImageLink.style.textDecoration = 'underline';
  changeImageLink.style.cursor = 'pointer';
  changeImageLink.style.color = '#a0a0a0';

  var newBackgroundImage = graph.backgroundImage;

  function updateBackgroundImage() {
    if (newBackgroundImage == null) {
      changeImageLink.removeAttribute('title');
      changeImageLink.style.fontSize = '';
      changeImageLink.innerHTML = mxResources.get('change') + '...';
    } else {
      changeImageLink.setAttribute('title', newBackgroundImage.src);
      changeImageLink.style.fontSize = '11px';
      changeImageLink.innerHTML =
        newBackgroundImage.src.substring(0, 42) + '...';
    }
  }

  mxEvent.addListener(changeImageLink, 'click', function (evt) {
    editorUi.showBackgroundImageDialog(function (image) {
      newBackgroundImage = image;
      updateBackgroundImage();
    });

    mxEvent.consume(evt);
  });

  updateBackgroundImage();

  td.appendChild(changeImageLink);

  row.appendChild(td);
  tbody.appendChild(row);

  row = document.createElement('tr');
  td = document.createElement('td');
  td.colSpan = 2;
  td.style.paddingTop = '16px';
  td.setAttribute('align', 'right');

  var cancelBtn = mxUtils.button(mxResources.get('cancel'), function () {
    editorUi.hideDialog();
  });
  cancelBtn.className = 'geBtn';

  if (editorUi.editor.cancelFirst) {
    td.appendChild(cancelBtn);
  }

  var applyBtn = mxUtils.button(mxResources.get('apply'), function () {
    editorUi.hideDialog();

    if (graph.gridSize !== gridSizeInput.value) {
      graph.setGridSize(parseInt(gridSizeInput.value));
    }

    var change = new ChangePageSetup(
      editorUi,
      newBackgroundColor,
      newBackgroundImage,
      accessor.get()
    );
    change.ignoreColor = graph.background == newBackgroundColor;

    var oldSrc =
      graph.backgroundImage != null ? graph.backgroundImage.src : null;
    var newSrc = newBackgroundImage != null ? newBackgroundImage.src : null;

    change.ignoreImage = oldSrc === newSrc;

    if (
      graph.pageFormat.width != change.previousFormat.width ||
      graph.pageFormat.height != change.previousFormat.height ||
      !change.ignoreColor ||
      !change.ignoreImage
    ) {
      graph.model.execute(change);
    }
  });
  applyBtn.className = 'geBtn gePrimaryBtn';
  td.appendChild(applyBtn);

  if (!editorUi.editor.cancelFirst) {
    td.appendChild(cancelBtn);
  }

  row.appendChild(td);
  tbody.appendChild(row);

  table.appendChild(tbody);
  this.container = table;
};

/**
 *
 */
PageSetupDialog.addPageFormatPanel = function (
  div,
  namePostfix,
  pageFormat,
  pageFormatListener
) {
  var formatName = 'format-' + namePostfix;

  var portraitCheckBox = document.createElement('input');
  portraitCheckBox.setAttribute('name', formatName);
  portraitCheckBox.setAttribute('type', 'radio');
  portraitCheckBox.setAttribute('value', 'portrait');

  var landscapeCheckBox = document.createElement('input');
  landscapeCheckBox.setAttribute('name', formatName);
  landscapeCheckBox.setAttribute('type', 'radio');
  landscapeCheckBox.setAttribute('value', 'landscape');

  var paperSizeSelect = document.createElement('select');
  paperSizeSelect.style.marginBottom = '8px';
  paperSizeSelect.style.width = '202px'; //// selcet 下拉框的样式
  paperSizeSelect.style.padding = '3px 0px';
  paperSizeSelect.style.border = '1px solid #aaa';
  paperSizeSelect.style.borderRadius = '3px';

  var formatDiv = document.createElement('div');
  //// formatDiv.style.marginLeft = '4px';
  formatDiv.style.marginTop = '10px'; //// 新加的
  formatDiv.style.width = '210px';
  formatDiv.style.height = '25px';
  formatDiv.style.lineHeight = '25px'; //// 图表里面 的 页面尺寸的地方， radio 纵向和横向
  formatDiv.style.fontSize = '12px';

  portraitCheckBox.style.marginRight = '6px';
  formatDiv.appendChild(portraitCheckBox);

  var portraitSpan = document.createElement('span');
  portraitSpan.style.maxWidth = '100px';
  mxUtils.write(portraitSpan, mxResources.get('portrait'));
  formatDiv.appendChild(portraitSpan);

  landscapeCheckBox.style.marginLeft = '40px'; //// 横向 向右的距离
  landscapeCheckBox.style.marginRight = '6px';
  formatDiv.appendChild(landscapeCheckBox);

  var landscapeSpan = document.createElement('span');
  landscapeSpan.style.width = '100px';
  mxUtils.write(landscapeSpan, mxResources.get('landscape'));
  formatDiv.appendChild(landscapeSpan);

  var customDiv = document.createElement('div');
  //// customDiv.style.marginLeft = '4px';
  customDiv.style.marginTop = '10px';
  customDiv.style.width = '210px';
  customDiv.style.height = '25px';

  var widthInput = document.createElement('input');
  widthInput.setAttribute('size', '7');
  widthInput.style.textAlign = 'right';
  widthInput.style.borderRadius = '3px'; //// 新加的圆角
  widthInput.style.border = '1px solid #aaa'; //// 新加的边框

  customDiv.appendChild(widthInput);
  mxUtils.write(customDiv, ' in x ');

  var heightInput = document.createElement('input');
  heightInput.setAttribute('size', '7');
  heightInput.style.textAlign = 'right';
  heightInput.style.borderRadius = '3px'; //// 新加的圆角
  heightInput.style.border = '1px solid #aaa'; //// 新加的边框
  customDiv.appendChild(heightInput);
  mxUtils.write(customDiv, ' in');

  formatDiv.style.display = 'none';
  customDiv.style.display = 'none';

  var pf = new Object();
  var formats = PageSetupDialog.getFormats();

  for (var i = 0; i < formats.length; i++) {
    var f = formats[i];
    pf[f.key] = f;

    var paperSizeOption = document.createElement('option');
    paperSizeOption.setAttribute('value', f.key);
    mxUtils.write(paperSizeOption, f.title);
    paperSizeSelect.appendChild(paperSizeOption);
  }

  var customSize = false;

  function listener(sender, evt, force) {
    if (
      force ||
      (widthInput != document.activeElement &&
        heightInput != document.activeElement)
    ) {
      var detected = false;

      for (var i = 0; i < formats.length; i++) {
        var f = formats[i];

        //// Special case where custom was chosen
        if (customSize) {
          if (f.key == 'custom') {
            paperSizeSelect.value = f.key;
            customSize = false;
          }
        } else if (f.format != null) {
          //// Fixes wrong values for previous A4 and A5 page sizes
          if (f.key == 'a4') {
            if (pageFormat.width == 826) {
              pageFormat = mxRectangle.fromRectangle(pageFormat);
              pageFormat.width = 827;
            } else if (pageFormat.height == 826) {
              pageFormat = mxRectangle.fromRectangle(pageFormat);
              pageFormat.height = 827;
            }
          } else if (f.key == 'a5') {
            if (pageFormat.width == 584) {
              pageFormat = mxRectangle.fromRectangle(pageFormat);
              pageFormat.width = 583;
            } else if (pageFormat.height == 584) {
              pageFormat = mxRectangle.fromRectangle(pageFormat);
              pageFormat.height = 583;
            }
          }

          if (
            pageFormat.width == f.format.width &&
            pageFormat.height == f.format.height
          ) {
            paperSizeSelect.value = f.key;
            portraitCheckBox.setAttribute('checked', 'checked');
            portraitCheckBox.defaultChecked = true;
            portraitCheckBox.checked = true;
            landscapeCheckBox.removeAttribute('checked');
            landscapeCheckBox.defaultChecked = false;
            landscapeCheckBox.checked = false;
            detected = true;
          } else if (
            pageFormat.width == f.format.height &&
            pageFormat.height == f.format.width
          ) {
            paperSizeSelect.value = f.key;
            portraitCheckBox.removeAttribute('checked');
            portraitCheckBox.defaultChecked = false;
            portraitCheckBox.checked = false;
            landscapeCheckBox.setAttribute('checked', 'checked');
            landscapeCheckBox.defaultChecked = true;
            landscapeCheckBox.checked = true;
            detected = true;
          }
        }
      }

      //// Selects custom format which is last in list
      if (!detected) {
        widthInput.value = pageFormat.width / 100;
        heightInput.value = pageFormat.height / 100;
        portraitCheckBox.setAttribute('checked', 'checked');
        paperSizeSelect.value = 'custom';
        formatDiv.style.display = 'none';
        customDiv.style.display = '';
      } else {
        formatDiv.style.display = '';
        customDiv.style.display = 'none';
      }
    }
  }

  listener();

  div.appendChild(paperSizeSelect);
  mxUtils.br(div);

  div.appendChild(formatDiv);
  div.appendChild(customDiv);

  var currentPageFormat = pageFormat;

  var update = function (evt, selectChanged) {
    var f = pf[paperSizeSelect.value];

    if (f.format != null) {
      widthInput.value = f.format.width / 100;
      heightInput.value = f.format.height / 100;
      customDiv.style.display = 'none';
      formatDiv.style.display = '';
    } else {
      formatDiv.style.display = 'none';
      customDiv.style.display = '';
    }

    var wi = parseFloat(widthInput.value);

    if (isNaN(wi) || wi <= 0) {
      widthInput.value = pageFormat.width / 100;
    }

    var hi = parseFloat(heightInput.value);

    if (isNaN(hi) || hi <= 0) {
      heightInput.value = pageFormat.height / 100;
    }

    var newPageFormat = new mxRectangle(
      0,
      0,
      Math.floor(parseFloat(widthInput.value) * 100),
      Math.floor(parseFloat(heightInput.value) * 100)
    );

    if (paperSizeSelect.value != 'custom' && landscapeCheckBox.checked) {
      newPageFormat = new mxRectangle(
        0,
        0,
        newPageFormat.height,
        newPageFormat.width
      );
    }

    //// Initial select of custom should not update page format to avoid update of combo
    if (
      (!selectChanged || !customSize) &&
      (newPageFormat.width != currentPageFormat.width ||
        newPageFormat.height != currentPageFormat.height)
    ) {
      currentPageFormat = newPageFormat;

      //// Updates page format and reloads format panel
      if (pageFormatListener != null) {
        pageFormatListener(currentPageFormat);
      }
    }
  };

  mxEvent.addListener(portraitSpan, 'click', function (evt) {
    portraitCheckBox.checked = true;
    update(evt);
    mxEvent.consume(evt);
  });

  mxEvent.addListener(landscapeSpan, 'click', function (evt) {
    landscapeCheckBox.checked = true;
    update(evt);
    mxEvent.consume(evt);
  });

  mxEvent.addListener(widthInput, 'blur', update);
  mxEvent.addListener(widthInput, 'click', update);
  mxEvent.addListener(heightInput, 'blur', update);
  mxEvent.addListener(heightInput, 'click', update);
  mxEvent.addListener(landscapeCheckBox, 'change', update);
  mxEvent.addListener(portraitCheckBox, 'change', update);
  mxEvent.addListener(paperSizeSelect, 'change', function (evt) {
    //// Handles special case where custom was chosen
    customSize = paperSizeSelect.value == 'custom';
    update(evt, true);
  });

  update();

  return {
    set: function (value) {
      pageFormat = value;
      listener(null, null, true);
    },
    get: function () {
      return currentPageFormat;
    },
    widthInput: widthInput,
    heightInput: heightInput
  };
};

/**
 *
 */
//// 页面尺寸布局
PageSetupDialog.getFormats = function () {
  return [
    {
      key: 'letter',
      title: 'US-Letter (8,5" x 11")',
      format: mxConstants.PAGE_FORMAT_LETTER_PORTRAIT
    },
    {
      key: 'legal',
      title: 'US-Legal (8,5" x 14")',
      format: new mxRectangle(0, 0, 850, 1400)
    },
    {
      key: 'tabloid',
      title: 'US-Tabloid (279 mm x 432 mm)',
      format: new mxRectangle(0, 0, 1100, 1700)
    },
    {
      key: 'a0',
      title: 'A0 (841 mm x 1189 mm)',
      format: new mxRectangle(0, 0, 3300, 4681)
    },
    {
      key: 'a1',
      title: 'A1 (594 mm x 841 mm)',
      format: new mxRectangle(0, 0, 2339, 3300)
    },
    {
      key: 'a2',
      title: 'A2 (420 mm x 594 mm)',
      format: new mxRectangle(0, 0, 1654, 2336)
    },
    {
      key: 'a3',
      title: 'A3 (297 mm x 420 mm)',
      format: new mxRectangle(0, 0, 1169, 1654)
    },
    {
      key: 'a4',
      title: 'A4 (210 mm x 297 mm)',
      format: mxConstants.PAGE_FORMAT_A4_PORTRAIT
    },
    {
      key: 'a5',
      title: 'A5 (148 mm x 210 mm)',
      format: new mxRectangle(0, 0, 583, 827)
    },
    {
      key: 'a6',
      title: 'A6 (105 mm x 148 mm)',
      format: new mxRectangle(0, 0, 413, 583)
    },
    {
      key: 'a7',
      title: 'A7 (74 mm x 105 mm)',
      format: new mxRectangle(0, 0, 291, 413)
    },
    {
      key: 'custom',
      title: mxResources.get('custom'),
      format: null
    }
  ];
};

/**
 * Static overrides
 */
(function () {

  //// Adds panning for the grid with no page view and disabled scrollbars
  var mxGraphPanGraph = mxGraph.prototype.panGraph;
  mxGraph.prototype.panGraph = function (dx, dy) {
    mxGraphPanGraph.apply(this, arguments);

    if (this.shiftPreview1 != null) {
      var canvas = this.view.canvas;

      if (canvas.ownerSVGElement != null) {
        canvas = canvas.ownerSVGElement;
      }

      var phase = this.gridSize * this.view.scale * this.view.gridSteps;
      var position =
        -Math.round(
          phase -
          mxUtils.mod(this.view.translate.x * this.view.scale + dx, phase)
        ) +
        'px ' +
        -Math.round(
          phase -
          mxUtils.mod(this.view.translate.y * this.view.scale + dy, phase)
        ) +
        'px';
      canvas.style.backgroundPosition = position;
    }
  };

  //// Draws page breaks only within the page
  mxGraph.prototype.updatePageBreaks = function (visible, width, height) {
    var scale = this.view.scale;
    var tr = this.view.translate;
    var fmt = this.pageFormat;
    var ps = scale * this.pageScale;

    var bounds2 = this.view.getBackgroundPageBounds();

    width = bounds2.width;
    height = bounds2.height;
    var bounds = new mxRectangle(
      scale * tr.x,
      scale * tr.y,
      fmt.width * ps,
      fmt.height * ps
    );

    //// Does not show page breaks if the scale is too small
    visible =
      visible && Math.min(bounds.width, bounds.height) > this.minPageBreakDist;

    var horizontalCount = visible ? Math.ceil(height / bounds.height) - 1 : 0;
    var verticalCount = visible ? Math.ceil(width / bounds.width) - 1 : 0;
    var right = bounds2.x + width;
    var bottom = bounds2.y + height;

    if (this.horizontalPageBreaks == null && horizontalCount > 0) {
      this.horizontalPageBreaks = [];
    }

    if (this.verticalPageBreaks == null && verticalCount > 0) {
      this.verticalPageBreaks = [];
    }

    var drawPageBreaks = mxUtils.bind(this, function (breaks) {
      if (breaks != null) {
        var count =
          breaks == this.horizontalPageBreaks ? horizontalCount : verticalCount;

        for (var i = 0; i <= count; i++) {
          var pts =
            breaks == this.horizontalPageBreaks
              ? [
                new mxPoint(
                  Math.round(bounds2.x),
                  Math.round(bounds2.y + (i + 1) * bounds.height)
                ),
                new mxPoint(
                  Math.round(right),
                  Math.round(bounds2.y + (i + 1) * bounds.height)
                )
              ]
              : [
                new mxPoint(
                  Math.round(bounds2.x + (i + 1) * bounds.width),
                  Math.round(bounds2.y)
                ),
                new mxPoint(
                  Math.round(bounds2.x + (i + 1) * bounds.width),
                  Math.round(bottom)
                )
              ];

          if (breaks[i] != null) {
            breaks[i].points = pts;
            breaks[i].redraw();
          } else {
            var pageBreak = new mxPolyline(pts, this.pageBreakColor);
            pageBreak.dialect = this.dialect;
            pageBreak.isDashed = this.pageBreakDashed;
            pageBreak.pointerEvents = false;
            pageBreak.init(this.view.backgroundPane);
            pageBreak.redraw();

            breaks[i] = pageBreak;
          }
        }

        for (var i = count; i < breaks.length; i++) {
          breaks[i].destroy();
        }

        breaks.splice(count, breaks.length - count);
      }
    });

    drawPageBreaks(this.horizontalPageBreaks);
    drawPageBreaks(this.verticalPageBreaks);
  };

  //// Add panning for background page in VML
  var graphPanGraph = mxGraph.prototype.panGraph;
  mxGraph.prototype.panGraph = function (dx, dy) {
    graphPanGraph.apply(this, arguments);

    if (
      this.dialect != mxConstants.DIALECT_SVG &&
      this.view.backgroundPageShape != null &&
      (!this.useScrollbarsForPanning || !mxUtils.hasScrollbars(this.container))
    ) {
      this.view.backgroundPageShape.node.style.marginLeft = dx + 'px';
      this.view.backgroundPageShape.node.style.marginTop = dy + 'px';
    }
  };

  /**
   * Consumes click events for disabled menu items.
   */
  var mxPopupMenuAddItem = mxPopupMenu.prototype.addItem;
  mxPopupMenu.prototype.addItem = function (
    title,
    image,
    funct,
    parent,
    iconCls,
    enabled
  ) {
    var result = mxPopupMenuAddItem.apply(this, arguments);

    if (enabled != null && !enabled) {
      mxEvent.addListener(result, 'mousedown', function (evt) {
        mxEvent.consume(evt);
      });
    }

    return result;
  };

  //// Returns last selected ancestor
  mxPopupMenuHandler.prototype.getCellForPopupEvent = function (me) {
    var cell = me.getCell();
    var model = this.graph.getModel();
    var parent = model.getParent(cell);

    while (model.isVertex(parent) && !this.graph.isContainer(parent)) {
      if (this.graph.isCellSelected(parent)) {
        cell = parent;
      }

      parent = model.getParent(parent);
    }

    return cell;
  };
})();

export default Editor;
export { OpenFile, Dialog, ErrorDialog, PrintDialog, PageSetupDialog };
